part of "../framework.dart";

/// 通知[Alert]
/// 使用此class之前，需要先在项目中做好配置
///
/// 使用方法：在app开始运行时（但在加载首页面之前）调用init方法
class Alert {
  /// 所有实际的通知都是由这个plugin发出的
  static final assistant = FlutterLocalNotificationsPlugin();

  /// 每次发送通知时，都需要传入这个通知的细节，由于目前每次通知都保持相同即可，所以将它作为class通用的变量
  static late NotificationDetails alertDetail;

  /// 其中包含了所有需要初始化的内容，包括请求权限、设置时区等等
  /// 只要调用这一次，所有的配置都会完成
  /// 在app开始运行时（但在加载首页面之前）调用
  static Future<void> init() async {
    // 1. 在所有平台上，请求通知权限
    if (Platform.isIOS || Platform.isMacOS) {
      await assistant
          .resolvePlatformSpecificImplementation<
              IOSFlutterLocalNotificationsPlugin>()
          ?.requestPermissions(
            alert: true,
            badge: true,
            sound: true,
          );
      await assistant
          .resolvePlatformSpecificImplementation<
              MacOSFlutterLocalNotificationsPlugin>()
          ?.requestPermissions(
            alert: true,
            badge: true,
            sound: true,
          );
    } else if (Platform.isAndroid) {
      final AndroidFlutterLocalNotificationsPlugin? androidImplementation =
          assistant.resolvePlatformSpecificImplementation<
              AndroidFlutterLocalNotificationsPlugin>();
      await androidImplementation?.requestNotificationsPermission();
    }

    // 2. 配置各平台的通知设置，并应用这些设置
    const androidSetting = AndroidInitializationSettings(
      // 这里的地址通知头像，它是安卓项目包中的地址，而与flutter无关
      '@mipmap/ic_launcher',
    );
    const darwinSetting = DarwinInitializationSettings();
    const linuxSetting = LinuxInitializationSettings(
      defaultActionName: '打开通知权限',
    );
    const setting = InitializationSettings(
      android: androidSetting,
      iOS: darwinSetting,
      linux: linuxSetting,
      macOS: darwinSetting,
    );
    await assistant.initialize(setting);

    // 3. 设置每次通知的细节（发送通知必须要传入的一个参数）
    // 当不设置参数时，基本都会按原先设定的setting来执行
    const androidDetail = AndroidNotificationDetails(
      'channel_id',
      'channel_name',
      importance: Importance.max,
      priority: Priority.high,
    );
    const darwinDetail = DarwinNotificationDetails();
    const linuxDetail = LinuxNotificationDetails();
    alertDetail = NotificationDetails(
      android: androidDetail,
      iOS: darwinDetail,
      macOS: darwinDetail,
      linux: linuxDetail,
    );

    // 4. 设置时区（为了schedule功能，它要求必须设置时区）
    initializeTimeZones();
    setLocalLocation(getLocation("Asia/Shanghai"));
  }

  /// 直接弹出一个特定的通知，并返回id
  static Future<void> pop({
    required String title,
    required String content,
  }) async =>
      assistant.show(Random().nextInt(100000), title, content, alertDetail);

  /// 在一段时间后，生成特定的通知
  /// 当设置完毕后，会返回通知的id（以免可能要取消）
  static Future<ScheduledAlert> schedule(
    Duration duration, {
    required String title,
    required String content,
  }) async {
    // 生成id
    int id = Random().nextInt(100000);
    // 规划通知
    await assistant.zonedSchedule(
      id,
      title,
      content,
      TZDateTime.now(local).add(duration),
      alertDetail,
      payload: '定时通知',
      uiLocalNotificationDateInterpretation:
          UILocalNotificationDateInterpretation.absoluteTime,
    );
    // 返回Alert对象
    return ScheduledAlert(id);
  }

  /// 取消某个id的通知
  static Future<void> cancel(int id) async => assistant.cancel(id);
}

class ScheduledAlert {
  int _id;
  ScheduledAlert(this._id);

  Future<void> cancel() async => Alert.cancel(_id);
}
